#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <functional>
#include "LockGuard.hpp"
#include "InetAddr.hpp"
#include "ThreadPool.hpp"

using task_t = std::function<void()>;

class MessageRoute
{
private:
  bool IsExists(const InetAddr &addr)
  {
    for (auto user : _online_user)
    {
      if (user == addr)
        return true;
    }
    return false;
  }

public:
  MessageRoute()
  {
    pthread_mutex_init(&_mutex, nullptr);
  }

  void AddUser(const InetAddr &addr)
  {
    LockGuard lockguard(&_mutex);
    if (IsExists(addr))
      return;
    _online_user.push_back(addr);
  }
  void DelUser(const InetAddr &addr)
  {
    LockGuard lockguard(&_mutex);
    for (auto iter = _online_user.begin(); iter != _online_user.end(); iter++)
    {
      if (*iter == addr)
      {
        _online_user.erase(iter);
        break;
      }
    }
  }
  void RouteHelper(int sockfd, std::string message, InetAddr who)
  {
    LockGuard lockguard(&_mutex);
    // 进行消息转发
    for (auto &user : _online_user)
    {
      std::string send_message = "\n[" + who.Ip() + ":" + std::to_string(who.Port()) + "]#" + message + "\n";
      const struct sockaddr_in addr = user.Addr();
      ::sendto(sockfd, send_message.c_str(), send_message.size(), 0, (struct sockaddr *)&addr, sizeof(user));
    }
  }
  void Route(int sockfd, std::string message, InetAddr who)
  {
    // 用户首次发消息，要将用户先加入到在线用户中
    AddUser(who);

    // 如果客户端要退出
    if (message == "Q" || message == "QUIT")
    {
      DelUser(who);
    }

    // 构建任务对象，入队列，让线程池进行转发
    task_t t = std::bind(&MessageRoute::RouteHelper, this, sockfd, message, who);
    ThreadPool<task_t>::GetInstance()->Enqueue(t);
  }
  ~MessageRoute()
  {
    pthread_mutex_destroy(&_mutex);
  }

private:
  std::vector<InetAddr> _online_user;
  pthread_mutex_t _mutex;
};